/// <reference path="./Vector2.ts" />


namespace apeng {


    const v2T = new Vector2()


    /**多边形 */
    export class Polygon {

        /**
         * 获取多边形内的某一点
         * @param polygon 多边形
         * @param angle 角度 
         * @param ratio 比率
         * @param maxDis 线段最大值
         */
        public static getDot(polygon: Vector2[], dir: Vector2, ratio: number, maxDis: number): Vector2 {
            let center = Vector2.polygonByCenterPoint(new Vector2(), polygon) as Vector2

            let value = new Vector2()

            let _dir = dir.normalize(new Vector2())
            let line = (_dir.mul(new Vector2(), maxDis) as Vector2).addSelf(center)

            for (let i = 0, l = polygon.length; i < l; ++i) {
                let a1 = polygon[i]
                let a2 = polygon[(i + 1) % l]

                if (this.lineLine(a1, a2, center, line)) {
                    let dis = this.pointLineDistance(center, a1, a2, true)
                    value.set(_dir).mulSelf(dis * ratio).addSelf(center)
                    break
                }
            }

            return value
        }


        /**转换为椭圆 求交 */
        public static elliptic(rect: Rectangle, circle: Circle) {
            // 有更简便的公式，暂时以 端点两个圆 中间矩形判断
            let len = Math.min(rect.width, rect.height)
            let center = rect.center
            Rectangle.TEMP.width = len
            Rectangle.TEMP.height = len
            Rectangle.TEMP.center = center

            if (this.rectCircle(Rectangle.TEMP, circle))
                return true
            let radius = len / 2
            Circle.TEMP.radius = radius
            if (rect.width > rect.height) {
                Circle.TEMP.x = rect.xMin + radius
                Circle.TEMP.y = center.y
                if (Circle.TEMP.intersects(circle))
                    return true
                Circle.TEMP.x = rect.xMax - radius
                if (Circle.TEMP.intersects(circle))
                    return true
            }
            else {
                Circle.TEMP.x = center.x
                Circle.TEMP.y = rect.yMin + radius
                if (Circle.TEMP.intersects(circle))
                    return true
                Circle.TEMP.y = rect.yMax - radius
                if (Circle.TEMP.intersects(circle))
                    return true
            }
            return false
        }

        /**
         * 矩形与圆是否相交
         * @param rect 
         * @param circle 
         */
        public static rectCircle(rect: Rectangle, circle: Circle): boolean {
            return this.polygonCircle(rect.polygon(), circle)
        }

        /**
         * 一维空间中 两条线段是否相交
         * @param min1 
         * @param max1 
         * @param min2 
         * @param max2 
         */
        public static oneLineLine(min1: number, max1: number, min2: number, max2: number): boolean {
            if (max1 < min2 || min1 > max2)
                return false
            return true
        }

        /**
          * 线段与线段是否相交
          * @param a1 第一条线段起点
          * @param a2 第一条线段终点
          * @param b1
          * @param b2
          */
        public static lineLine(a1: IVector2, a2: IVector2, b1: IVector2, b2: IVector2): boolean {
            if (!a1 || !a2 || !b1 || !b2)
                return false

            //向量叉乘
            let ua_t = (b2.x - b1.x) * (a1.y - b1.y) - (b2.y - b1.y) * (a1.x - b1.x)
            let ub_t = (a2.x - a1.x) * (a1.y - b1.y) - (a2.y - a1.y) * (a1.x - b1.x)
            let u_b = (b2.y - b1.y) * (a2.x - a1.x) - (b2.x - b1.x) * (a2.y - a1.y)

            // 方向
            if (u_b !== 0) {
                let ua = ua_t / u_b
                let ub = ub_t / u_b

                if (0 <= ua && ua <= 1 && 0 <= ub && ub <= 1)
                    return true
                return false
            }

            return false
        }

        /**
     * 线段与矩形是否相交
     * @param a1 第一条线段起点
     * @param a2 第一条线段终点
     * @param b 矩形块
     */
        public static lineRect(a1: Vector2, a2: Vector2, b: Rectangle): boolean {
            if (!a1 || !a2 || !b) return false
            let polygon = b.polygon()
            let r0 = polygon[0]
            let r1 = polygon[1]
            let r2 = polygon[2]
            let r3 = polygon[3]

            if (this.lineLine(a1, a2, r0, r1)) return true

            if (this.lineLine(a1, a2, r1, r2)) return true

            if (this.lineLine(a1, a2, r2, r3)) return true

            if (this.lineLine(a1, a2, r3, r0)) return true

            return false
        }

        /**
         * 线段与多边形是否相交
         * @param a1
         * @param a2
         * @param b
         */
        public static linePolygon(a1: IVector2, a2: IVector2, b: IVector2[]) {
            if (!a1 || !a2 || !b)
                return false

            for (let i = 0, length = b.length; i < length; ++i) {
                let b1 = b[i]
                let b2 = b[(i + 1) % length]

                if (this.lineLine(a1, a2, b1, b2))
                    return true
            }

            return false
        }

        /**
         * 矩形是否与线段相交
         * @param a
         * @param b
         */
        public static rectPolygon(a: Rectangle, b: Vector2[]) {
            if (!a || !b) return false
            let i: number, l: number
            let polygon = a.polygon()
            let r0 = polygon[0]
            let r1 = polygon[1]
            let r2 = polygon[2]
            let r3 = polygon[3]

            if (this.linePolygon(r0, r1, b)) return true

            if (this.linePolygon(r1, r2, b)) return true

            if (this.linePolygon(r2, r3, b)) return true

            if (this.linePolygon(r3, r0, b)) return true

            // 矩形包含多边形的点
            for (i = 0, l = b.length; i < l; ++i) {
                if (a.contains(b[i]))
                    return true
                // if (this.pointInPolygon(b[i], a.polygon())) return true
            }

            // 多边形包含矩形点
            if (this.pointInPolygon(r0, b)) return true

            if (this.pointInPolygon(r1, b)) return true

            if (this.pointInPolygon(r2, b)) return true

            if (this.pointInPolygon(r3, b)) return true

            return false
        }
        /**
         * 多边形与多边形相交
         * @param a
         * @param b
         */
        public static polygonPolygon(a: Vector2[], b: Vector2[]): boolean {
            if (!a || !b)
                return false
            let i: number, l: number

            // a的每条边相交于b的每条边
            for (i = 0, l = a.length; i < l; ++i) {
                let a1 = a[i]
                let a2 = a[(i + 1) % l]

                if (this.linePolygon(a1, a2, b))
                    return true
            }

            // b的每个点在a中
            for (i = 0, l = b.length; i < l; ++i) {
                if (this.pointInPolygon(b[i], a))
                    return true
            }

            // a的每个点在b中
            for (i = 0, l = a.length; i < l; ++i) {
                if (this.pointInPolygon(a[i], b))
                    return true
            }

            return false
        }


        /**
     * 多边形与圆形是否相交
     * @param polygon
     * @param circle
     */
        public static polygonCircle(polygon: IVector2[], circle: Circle) {
            if (!polygon || !circle) return false

            let position = circle.position
            if (this.pointInPolygon(position, polygon)) {
                return true
            }

            for (let i = 0, l = polygon.length; i < l; i++) {
                let start = i === 0 ? polygon[polygon.length - 1] : polygon[i - 1]
                let end = polygon[i]

                if (this.pointLineDistance(position, start, end, true) < circle.radius) {
                    return true
                }
            }

            return false
        }


        /**
         * 点是否在多边形中
         * @param point
         * @param polygon
         */
        public static pointInPolygon(point: IVector2, polygon: IVector2[]): boolean {
            if (!point || !polygon)
                return false
            let inside = false
            let x = point.x
            let y = point.y

            let length = polygon.length

            for (let i = 0, j = length - 1; i < length; j = i++) {
                let xi = polygon[i].x,
                    yi = polygon[i].y,
                    xj = polygon[j].x,
                    yj = polygon[j].y,
                    intersect = yi > y !== yj > y && x < ((xj - xi) * (y - yi)) / (yj - yi) + xi

                if (intersect) inside = !inside
            }

            return inside
        }

        /**
         * 计算点到直线的距离。如果这是一条线段并且垂足不在线段内，则会计算点到线段端点的距离
         * @param point 点
         * @param start 线段起点
         * @param end 线段终点
         * @param isSegment 是否为线段
         */
        public static pointLineDistance(point: IVector2, start: IVector2, end: IVector2, isSegment: boolean) {
            if (!point || !start || !end) return 0

            // 可通过 点积的方式得到

            let dx = end.x - start.x
            let dy = end.y - start.y
            let d = dx * dx + dy * dy
            let t = ((point.x - start.x) * dx + (point.y - start.y) * dy) / d
            // 垂足

            if (!isSegment) {
                v2T.set(start.x + t * dx, start.y + t * dy)
            } else {
                if (d) {
                    // 在第一个端点左边
                    if (t < 0) v2T.set(start)
                    // 在第二个端点右边
                    else if (t > 1) v2T.set(end)
                    // 在线段中间
                    else v2T.set(start.x + t * dx, start.y + t * dy)
                } else {
                    v2T.set(start)
                }
            }

            //垂足与点的距离
            dx = point.x - v2T.x
            dy = point.y - v2T.y
            return Math.sqrt(dx * dx + dy * dy)
        }

        /**旋转矩形与旋转矩形 */
        public static rectByAngle(a: Rectangle, b: Rectangle) {
            return this.polygonPolygon(a.angleCenter(), b.angleCenter())
        }

    }
}